package com.btm.qiaoqiang.ruleadp.parser;

import com.btm.qiaoqiang.ruleadp.CharUtil;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.LinkedList;
import java.util.Objects;

/**
 * 规则节点
 *
 * @author: btm
 * @time: 14:32 2020/9/15
 **/
public class RuleNode implements Cloneable{

    /**追踪单号**/
    private int id;
    /** 属性名称 **/
    public String fieldName = null;
    /**当前节点对应的取值方法名，默认为getXXX()，XXX为表达式中设置的变量名，请遵循驼峰明明发了**/
    private String methodName = null;
    /**当前节点给定值，root节点为null**/
    private Object value = null;
    /**当前节点给定值是否为数字类型，true：是数字类型**/
    private boolean valueTypeIsNumber = false;
    /** 值是否为自定义的动态值 **/
    private boolean customDynamicValue = false;
    /**true：给定值等于当前节点值，root节点永为false**/
    private Boolean equal;
    /**true：给定值不等于当前节点值，root节点永为false**/
    private Boolean notEqual;
    /**true：给定值大于等于当前节点值，root节点永为false**/
    private Boolean gte;
    /**true：给定值大于当前节点值，root节点永为false**/
    private Boolean gt;
    /**true：给定值小于等于当前节点值，root节点永为false**/
    private Boolean lte;
    /**true：给定值小于当前节点值，root节点永为false**/
    private Boolean lt;
    /**当前节点的子节点**/
    private LinkedList<RuleNode> childNodeList = new LinkedList<>();
    /**父节点指针**/
    private RuleNode supperNode;

    /**是否为虚拟节点，虚拟节点不参与匹配检测且不允许设置任何值**/
    private boolean virtualNode = false;

    public RuleNode(int id) {
        this.id = id;
    }

    /**
     * 添加单个子节点
     * @param leafNode 子节点
     * @param virtualNodeAddChildNode true：当前是为虚节点添加子节点；false:当前是为非虚节点添加子节点
     * @return true:添加成功
     */
    public RuleNode addChildNode(RuleNode leafNode,boolean virtualNodeAddChildNode) {
        //给虚节点添加子节点，则就是给此虚节点的当前叶子节点添加叶子节点
        if (virtualNodeAddChildNode && !CollectionUtils.isEmpty(this.childNodeList)) {
            for (RuleNode childRuleNode : this.childNodeList) {
                childRuleNode.addChildNode(leafNode, virtualNodeAddChildNode);
            }
        }
        //给非虚节点添加子节点，则直接添加为当前节点的叶子节点
        if (!virtualNodeAddChildNode || this.isLeafNode()) {
            RuleNode ruleNode = leafNode.clone();
            ruleNode.setSupperNode(this);
            this.childNodeList.add(ruleNode);
            return ruleNode;
        } else {
            return this;
        }
    }

    /**
     * 删除指定的子节点
     * @param index
     * @return
     */
    public RuleNode deleteOneChildNode(int index) {
        if (index >= this.childNodeList.size()) {
            throw new ArrayIndexOutOfBoundsException("not found child node at ["+index+"]");
        } else if (index < 0) {
            throw new IllegalArgumentException("index must be greater than zero");
        }
        return this.childNodeList.remove(index);
    }

    public void cleanVirtualNode() {
        if (!isLeafNode()) {
            //如果当前节点不是叶子节点则直接结束返回
            int supperSize = this.childNodeList.size();
            for (int i = 0;i<supperSize;i++){
                this.childNodeList.get(i).cleanVirtualNode();
            }
            if (isVirtualNode()) {
                int size = this.childNodeList.size();
                for (int i = 0;i<size;i++){
                    RuleNode ruleNode = this.childNodeList.get(i);
                    ruleNode.supperNode = this.supperNode;
                    this.supperNode.addChildNode(ruleNode, false);
                    supperSize ++;
                }
            }
            if (!isVirtualNode()) {
                this.childNodeList.removeIf(RuleNode::isVirtualNode);
            }
        }
    }

    /**
     * 是否为叶子节点
     * @return true:是叶子节点
     */
    public boolean isLeafNode() {
        return CollectionUtils.isEmpty(childNodeList);
    }

    public boolean isEqual() {
        return Objects.nonNull(this.equal) && Boolean.TRUE.equals(this.equal);
    }

    public boolean isNotEqual() {
        return Objects.nonNull(this.notEqual) && Boolean.TRUE.equals(this.notEqual);
    }

    public boolean isGt() {
        return Objects.nonNull(this.gt) && Boolean.TRUE.equals(this.gt);
    }

    public boolean isGte() {
        return Objects.nonNull(this.gte) && Boolean.TRUE.equals(this.gte);
    }

    public boolean isLt() {
        return Objects.nonNull(this.lt) && Boolean.TRUE.equals(this.lt);
    }

    public boolean isLte() {
        return Objects.nonNull(this.lte) && Boolean.TRUE.equals(this.lte);
    }

    public boolean isValueTypeIsNumber() {
        return this.valueTypeIsNumber;
    }

    public boolean isVirtualNode() {
        return this.virtualNode;
    }

    public void setCustomDynamicValue(boolean customDynamicValue) {
        this.customDynamicValue = customDynamicValue;
    }

    public boolean isCustomDynamicValue() {
        return this.customDynamicValue;
    }

    public String getMethodName() {
        return this.methodName;
    }

    public String getFieldName() {
        return fieldName;
    }

    public Object getValue() {
        return this.value;
    }

    public LinkedList<RuleNode> getChildNodeList() {
        return this.childNodeList;
    }

    /**
     * 获得父节点
     * @return 父节点
     */
    public RuleNode getSupperNode() {
        return this.supperNode;
    }

    public void setEqual(boolean flag, boolean virtualNodeAddChildNode) {
        //给虚节点添加子节点，则就是给此虚节点的当前叶子节点添加叶子节点
        if (virtualNodeAddChildNode && !CollectionUtils.isEmpty(this.childNodeList)) {
            for (RuleNode childRuleNode : this.childNodeList) {
                childRuleNode.setEqual(flag, virtualNodeAddChildNode);
            }
        }
        //给非虚节点添加子节点，则直接添加为当前节点的叶子节点
        if (Objects.isNull(this.value) && (!this.isVirtualNode() || !virtualNodeAddChildNode)) {
            this.equal = flag;
        }
    }

    public void setNotEqual(boolean flag, boolean virtualNodeAddChildNode) {
        //给虚节点添加子节点，则就是给此虚节点的当前叶子节点添加叶子节点
        if (virtualNodeAddChildNode && !CollectionUtils.isEmpty(this.childNodeList)) {
            for (RuleNode childRuleNode : this.childNodeList) {
                childRuleNode.setNotEqual(flag, virtualNodeAddChildNode);
            }
        }
        //给非虚节点添加子节点，则直接添加为当前节点的叶子节点
        if (Objects.isNull(this.value) && (!this.isVirtualNode() || !virtualNodeAddChildNode)) {
            this.notEqual = flag;
        }
    }

    public void setGt(boolean flag, boolean virtualNodeAddChildNode) {
        //给虚节点添加子节点，则就是给此虚节点的当前叶子节点添加叶子节点
        if (virtualNodeAddChildNode && !CollectionUtils.isEmpty(this.childNodeList)) {
            for (RuleNode childRuleNode : this.childNodeList) {
                childRuleNode.setGt(flag, virtualNodeAddChildNode);
            }
        }
        //给非虚节点添加子节点，则直接添加为当前节点的叶子节点
        if (Objects.isNull(this.value) && (!this.isVirtualNode() || !virtualNodeAddChildNode)) {
            this.gt = flag;
            this.valueTypeIsNumber = true;
        }
    }

    public void setGte(boolean flag, boolean virtualNodeAddChildNode) {
        //给虚节点添加子节点，则就是给此虚节点的当前叶子节点添加叶子节点
        if (virtualNodeAddChildNode && !CollectionUtils.isEmpty(this.childNodeList)) {
            for (RuleNode childRuleNode : this.childNodeList) {
                childRuleNode.setGte(flag, virtualNodeAddChildNode);
            }
        }
        //给非虚节点添加子节点，则直接添加为当前节点的叶子节点
        if (Objects.isNull(this.value) && (!this.isVirtualNode() || !virtualNodeAddChildNode)) {
            this.gte = flag;
            this.valueTypeIsNumber = true;
        }
    }

    public void setLt(boolean flag, boolean virtualNodeAddChildNode) {
        //给虚节点添加子节点，则就是给此虚节点的当前叶子节点添加叶子节点
        if (virtualNodeAddChildNode && !CollectionUtils.isEmpty(this.childNodeList)) {
            for (RuleNode childRuleNode : this.childNodeList) {
                childRuleNode.setLt(flag, virtualNodeAddChildNode);
            }
        }
        //给非虚节点添加子节点，则直接添加为当前节点的叶子节点
        if (Objects.isNull(this.value) && (!this.isVirtualNode() || !virtualNodeAddChildNode)) {
            this.lt = flag;
            this.valueTypeIsNumber = true;
        }
    }

    public void setLte(boolean flag, boolean virtualNodeAddChildNode) {
        //给虚节点添加子节点，则就是给此虚节点的当前叶子节点添加叶子节点
        if (virtualNodeAddChildNode && !CollectionUtils.isEmpty(this.childNodeList)) {
            for (RuleNode childRuleNode : this.childNodeList) {
                childRuleNode.setLte(flag, virtualNodeAddChildNode);
            }
        }
        //给非虚节点添加子节点，则直接添加为当前节点的叶子节点
        if (Objects.isNull(this.value) && (!this.isVirtualNode() || !virtualNodeAddChildNode)) {
            this.lte = flag;
            this.valueTypeIsNumber = true;
        }
    }

    /**
     * 将节点设置为一个虚拟节点
     */
    public void virtualization() {
        this.virtualNode = true;
    }

    public void setSupperNode(RuleNode supperNode) {
        this.supperNode = supperNode;
    }

    /**
     * 设置被取值的字段名称
     * @param fieldName 字段名称
     */
    public void setFieldName(String fieldName) {
        canSet();
        this.fieldName = fieldName;
    }

    /**
     * 设置取值方法名<br/>
     * 虚拟节点不允许设置
     *
     * @param methodName 取值方法名
     */
    public void setMethodName(String methodName) {
        canSet();
        this.methodName = methodName;
    }

    //todo 异常信息待完善
    public void setValue(Object value, boolean virtualNodeAddChildNode) {
        //给虚节点添加子节点，则就是给此虚节点的当前叶子节点添加叶子节点
        if (virtualNodeAddChildNode && !CollectionUtils.isEmpty(this.childNodeList)) {
            for (RuleNode childRuleNode : this.childNodeList) {
                childRuleNode.setValue(value, virtualNodeAddChildNode);
            }
        }
        //给非虚节点添加子节点，则直接添加为当前节点的叶子节点
        if (Objects.isNull(this.value) && (!this.isVirtualNode() || !virtualNodeAddChildNode)) {
            if (value instanceof String) {
                String stringValue = String.valueOf(value);
                if (!StringUtils.hasText(stringValue)) {
                    throw new IllegalArgumentException("no value");
                }
                //校验字符串中是否都是数字
                if (valueTypeIsNumber) {
                    if (!CharUtil.isNumber(stringValue)) {
                        throw new RuntimeException("need a number, but value ["+value+"] is not a number");
                    }
                    this.value = Integer.valueOf(stringValue);
                } else {
                    if (CharUtil.isNumber(stringValue)) {
                        this.valueTypeIsNumber = true;
                        this.value = Integer.valueOf(stringValue);
                    } else {
                        this.value = value;
                    }
                }
            } else if (value instanceof Boolean) {
                this.value = value;
            } else {
                throw new IllegalArgumentException("Illegal value type");
            }
        }
    }

    /**
     * 是否能非当前节点设置值，虚拟节点不允许设置值
     */
    private void canSet() {
        if (isVirtualNode()) {
            throw new RuntimeException("This is a virtual node");
        }
    }

    @Override
    public RuleNode clone() {
        RuleNode ruleNode = new RuleNode(this.id);
        ruleNode.fieldName = this.fieldName;
        ruleNode.methodName = this.methodName;
        ruleNode.value = this.value;
        ruleNode.equal = this.equal;
        ruleNode.notEqual = this.notEqual;
        ruleNode.gt = this.gt;
        ruleNode.gte = this.gte;
        ruleNode.lt = this.lt;
        ruleNode.lte = this.lte;
        ruleNode.valueTypeIsNumber = this.valueTypeIsNumber;
        ruleNode.supperNode = this.supperNode;
        ruleNode.virtualNode = this.virtualNode;
        ruleNode.customDynamicValue = this.customDynamicValue;
        if (!CollectionUtils.isEmpty(this.childNodeList)) {
            for (RuleNode childRuleNode : childNodeList) {
                ruleNode.addChildNode(childRuleNode,false);
            }
        }
        return ruleNode;
    }

    @Override
    public String toString() {
        return "RuleNode{" +
                "fieldName='" + fieldName + '\'' +
                ", methodName='" + methodName + '\'' +
                ", value=" + value +
                ", valueTypeIsNumber=" + valueTypeIsNumber +
                ", customDynamicValue=" + customDynamicValue +
                ", equal=" + equal +
                ", notEqual=" + notEqual +
                ", gte=" + gte +
                ", gt=" + gt +
                ", lte=" + lte +
                ", lt=" + lt +
                ", childNodeList=[" + (CollectionUtils.isEmpty(childNodeList) ? "" : childNodeList.toString()) +
                "], supperNode=" + supperNode.getClass().getName() +
                ", virtualNode=" + virtualNode +
                '}';
    }

    /**
     * 绘制规则树,以文本的形式将规则表达式展示出来
     */
    public void drawRuleTree(String stringPre, StringBuilder resultBuilder) {
        StringBuilder stringBuilder = new StringBuilder(stringPre);
        if (Objects.nonNull(this.methodName)) {
            stringBuilder.append(this.methodName);
            if (isEqual()) {
                stringBuilder.append("=");
            } else if (isNotEqual()) {
                stringBuilder.append("!=");
            } else if (isGt()) {
                stringBuilder.append(">");
            }else if (isGte()) {
                stringBuilder.append(">=");
            }else if (isLt()) {
                stringBuilder.append("<");
            }else if (isLte()) {
                stringBuilder.append("<=");
            } else {
                stringBuilder.append("->");
            }
            stringBuilder.append(this.value).append("\t");
        }
        if (isLeafNode()) {
            resultBuilder.append(stringBuilder).append("\r\n");
        } else {
            int size = this.childNodeList.size();
            String preString = stringBuilder.toString();
            for (int i = 0 ;i < size; i++) {
                this.childNodeList.get(i).drawRuleTree(preString,resultBuilder);
            }
        }
    }
}
